package com.learning.spring.aop.aspectj.annotation.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.DeclareParents;

/**
 * ClassName: AnnotationAdvice
 * Description: Advice 类型
 * Date: 2019/5/6 9:17 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
@Aspect
public class AnnotationAdviceAspect {

    /**
     * 前置：
     * value：定义切点
     * argNames：由于无法通过Java 反射获取方法入参名，所以如果在java 编译时未启用调试信息，或者需要在运行期解析切点，
     * 就必须通过这个成员指定注解所标注增强方法的参数名（名字完全相同），多个参数名用逗号分隔
     */
    @Before("execution(* add(..))")
    public void before() {
        System.out.println("Hello   @Before");
    }

    /**
     * 后置
     * pointcut：切点，value同义
     * returning：将目标对象方法的返回值绑定给增强的方法
     */
    @AfterReturning(value = "execution(* add(..))", returning = "result")
    public void afterReturning(String result) {
        System.out.println("Hello   @AfterReturning" + result);
    }

    /**
     * 环绕
     */
    @Around("execution(* add(..))")
    public void around(ProceedingJoinPoint invocation) throws Throwable {
        System.out.println("Hello   @Around  before");
        invocation.proceed();
        System.out.println("Hello   @Around  after");
    }

    /**
     * 异常抛出
     * throwing：将抛出的异常绑定到增强方法中
     */
    @AfterThrowing(value = "execution(* add(..))", throwing = "ex")
    public void afterThrowing(Exception ex) {
        System.out.println("Hello   @AfterThrowing" + ex);
    }

    /**
     * After finally advice。不管是抛出异常还是正常退出，该增强都会被执行。
     * 可以看成是AfterReturning和AfterThrowing的混合物，一般用来释放资源
     */
    @After("execution(* add(..))")
    public void after() {
        System.out.println("Hello   @After finally advice");
    }

    /**
     * 引介 Advice
     * value: 定义切点，表示在哪个目标类上添加引介
     * defaultImpl：默认接口的实现类
     */
    @DeclareParents(value = "com.learning.spring.aop.aspectj.AopServiceImpl", defaultImpl = MonitorableImpl.class)
    public Monitorable monitorable;
}
